package storage

import (
	"fmt"
	"io"
	"os"
	"path/filepath"
	"sync"
)

// VolumeInfo 存储卷的信息
type VolumeInfo struct {
	ID       int    `json:"id"`
	Path     string `json:"path"`
	Size     int64  `json:"size"`      // 卷的总大小
	Used     int64  `json:"used"`      // 已使用的大小
	IsActive bool   `json:"is_active"` // 是否活跃（可写入）
}

// AppendStorage 实现append模式的存储
type AppendStorage struct {
	root         string
	volumeSize   int64
	volumes      map[int]*VolumeInfo
	nextVolumeID int
	volumesMu    sync.RWMutex // 保护volumes map和nextVolumeID

	// 每个volume的锁
	volumeLocks   map[int]*sync.RWMutex // volumeID -> 读写锁
	volumeLocksMu sync.Mutex            // 保护volumeLocks map
}

// NewAppendStorage 创建新的append存储实例
func NewAppendStorage(root string, volumeSize int64) (*AppendStorage, error) {
	as := &AppendStorage{
		root:         root,
		volumeSize:   volumeSize,
		volumes:      make(map[int]*VolumeInfo),
		nextVolumeID: 1,
		volumeLocks:  make(map[int]*sync.RWMutex),
	}

	// 确保根目录存在
	if err := os.MkdirAll(root, 0755); err != nil {
		return nil, fmt.Errorf("failed to create root directory: %w", err)
	}

	// 扫描现有的卷
	if err := as.scanExistingVolumes(); err != nil {
		return nil, fmt.Errorf("failed to scan existing volumes: %w", err)
	}

	return as, nil
}

// scanExistingVolumes 扫描现有的卷文件
func (as *AppendStorage) scanExistingVolumes() error {
	volumesDir := filepath.Join(as.root, "volumes")
	if _, err := os.Stat(volumesDir); os.IsNotExist(err) {
		// 卷目录不存在，创建它
		return os.MkdirAll(volumesDir, 0755)
	}

	entries, err := os.ReadDir(volumesDir)
	if err != nil {
		return err
	}

	for _, entry := range entries {
		if entry.IsDir() {
			continue
		}
		// 卷文件命名格式: volume_<id>.dat
		var volumeID int
		if _, err := fmt.Sscanf(entry.Name(), "volume_%d.dat", &volumeID); err != nil {
			continue
		}

		volumePath := filepath.Join(volumesDir, entry.Name())
		stat, err := os.Stat(volumePath)
		if err != nil {
			continue
		}

		volume := &VolumeInfo{
			ID:       volumeID,
			Path:     volumePath,
			Size:     as.volumeSize,
			Used:     stat.Size(),
			IsActive: stat.Size() < as.volumeSize,
		}

		as.volumes[volumeID] = volume
		if volumeID >= as.nextVolumeID {
			as.nextVolumeID = volumeID + 1
		}
	}

	return nil
}

// getVolumeLock 获取或创建volume锁
func (as *AppendStorage) getVolumeLock(volumeID int) *sync.RWMutex {
	as.volumeLocksMu.Lock()
	defer as.volumeLocksMu.Unlock()

	if as.volumeLocks[volumeID] == nil {
		as.volumeLocks[volumeID] = &sync.RWMutex{}
	}

	return as.volumeLocks[volumeID]
}

// CleanupInactiveVolumeLocks 清理所有非活跃volume的锁
func (as *AppendStorage) CleanupInactiveVolumeLocks() {
	as.volumesMu.RLock()
	activeVolumes := make(map[int]bool)
	for _, volume := range as.volumes {
		if volume.IsActive {
			activeVolumes[volume.ID] = true
		}
	}
	as.volumesMu.RUnlock()

	as.volumeLocksMu.Lock()
	defer as.volumeLocksMu.Unlock()

	for volumeID := range as.volumeLocks {
		if !activeVolumes[volumeID] {
			delete(as.volumeLocks, volumeID)
		}
	}
}

// createNewVolume 创建新的卷
func (as *AppendStorage) createNewVolume() (*VolumeInfo, error) {
	as.volumesMu.Lock()
	defer as.volumesMu.Unlock()

	volumeID := as.nextVolumeID
	as.nextVolumeID++

	volumesDir := filepath.Join(as.root, "volumes")
	if err := os.MkdirAll(volumesDir, 0755); err != nil {
		return nil, err
	}

	volumePath := filepath.Join(volumesDir, fmt.Sprintf("volume_%d.dat", volumeID))

	// 创建卷文件
	file, err := os.Create(volumePath)
	if err != nil {
		return nil, fmt.Errorf("failed to create volume file: %w", err)
	}
	file.Close()

	volume := &VolumeInfo{
		ID:       volumeID,
		Path:     volumePath,
		Size:     as.volumeSize,
		Used:     0,
		IsActive: true,
	}

	as.volumes[volumeID] = volume
	return volume, nil
}

// getActiveVolume 获取当前活跃的卷，如果没有则创建新的
func (as *AppendStorage) getActiveVolume() (*VolumeInfo, error) {
	as.volumesMu.RLock()
	// 查找活跃的卷
	for _, volume := range as.volumes {
		if volume.IsActive {
			as.volumesMu.RUnlock()
			return volume, nil
		}
	}
	as.volumesMu.RUnlock()

	// 没有活跃的卷，创建新的
	return as.createNewVolume()
}

// writeToVolumeWithLock 在volume锁保护下进行原子性写入
func (as *AppendStorage) writeToVolumeWithLock(volume *VolumeInfo, r io.Reader, size int64) (int64, error) {
	// 打开文件
	file, err := os.OpenFile(volume.Path, os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		return 0, fmt.Errorf("failed to open volume file: %w", err)
	}
	defer file.Close()

	// 获取当前文件末尾偏移量
	offset, err := file.Seek(0, io.SeekEnd)
	if err != nil {
		return 0, fmt.Errorf("failed to get file offset: %w", err)
	}

	// 写入数据
	written, err := io.CopyN(file, r, size)
	if err != nil {
		return 0, fmt.Errorf("failed to write data: %w", err)
	}

	if written != size {
		return 0, fmt.Errorf("incomplete write: expected %d bytes, wrote %d bytes", size, written)
	}

	return offset, nil
}

// readFromVolumeWithLock 在volume锁保护下进行读取
func (as *AppendStorage) readFromVolumeWithLock(volume *VolumeInfo, offset, size int64) (io.ReadCloser, error) {
	file, err := os.Open(volume.Path)
	if err != nil {
		return nil, fmt.Errorf("failed to open volume file: %w", err)
	}

	// 定位到指定偏移量
	if _, err := file.Seek(offset, io.SeekStart); err != nil {
		file.Close()
		return nil, fmt.Errorf("failed to seek to offset %d: %w", offset, err)
	}

	// 创建限制读取器
	limitedReader := io.LimitReader(file, size)

	return &volumeReader{
		file:   file,
		reader: limitedReader,
	}, nil
}

// PutObject 将对象数据append到卷中，支持跨卷存储，返回片段信息
func (as *AppendStorage) PutObject(bucket, key string, r io.Reader, size int64) ([]VolumeSegment, error) {
	var segments []VolumeSegment
	remaining := size

	for remaining > 0 {
		// 获取活跃的卷
		volume, err := as.getActiveVolume()
		if err != nil {
			return nil, fmt.Errorf("failed to get active volume: %w", err)
		}

		// 获取该volume的写锁
		volumeLock := as.getVolumeLock(volume.ID)
		volumeLock.Lock()

		// 在锁保护下重新检查卷状态
		as.volumesMu.RLock()
		currentVolume := as.volumes[volume.ID]
		as.volumesMu.RUnlock()

		if currentVolume == nil || !currentVolume.IsActive {
			volumeLock.Unlock()
			continue // 重新获取活跃卷
		}

		// 计算可用空间
		availableSpace := currentVolume.Size - currentVolume.Used
		if availableSpace <= 0 {
			// 标记为非活跃
			as.volumesMu.Lock()
			currentVolume.IsActive = false
			as.volumesMu.Unlock()
			volumeLock.Unlock()
			continue // 重新获取活跃卷
		}

		// 确定片段大小
		segmentSize := remaining
		if segmentSize > availableSpace {
			segmentSize = availableSpace
		}

		// 原子性写入操作
		offset, err := as.writeToVolumeWithLock(currentVolume, r, segmentSize)
		if err != nil {
			volumeLock.Unlock()
			return nil, fmt.Errorf("failed to write to volume: %w", err)
		}

		// 记录片段
		segments = append(segments, VolumeSegment{
			SegmentID: len(segments) + 1,
			VolumeID:  currentVolume.ID,
			Offset:    offset,
			Size:      segmentSize,
		})

		// 更新卷使用量
		as.volumesMu.Lock()
		currentVolume.Used += segmentSize
		if currentVolume.Used >= currentVolume.Size {
			currentVolume.IsActive = false
		}
		as.volumesMu.Unlock()

		volumeLock.Unlock()
		remaining -= segmentSize
	}

	return segments, nil
}

// ValidateAndSortSegments 验证并排序片段，确保正确的读取顺序
func ValidateAndSortSegments(segments []VolumeSegment) ([]VolumeSegment, error) {
	if len(segments) == 0 {
		return nil, fmt.Errorf("no segments provided")
	}

	// 检查是否有重复的SegmentID
	seen := make(map[int]bool)
	for _, seg := range segments {
		if seen[seg.SegmentID] {
			return nil, fmt.Errorf("duplicate segment ID: %d", seg.SegmentID)
		}
		seen[seg.SegmentID] = true
	}

	// 按SegmentID排序
	sortedSegments := make([]VolumeSegment, len(segments))
	copy(sortedSegments, segments)

	// 简单的冒泡排序（对于少量片段足够）
	for i := 0; i < len(sortedSegments)-1; i++ {
		for j := 0; j < len(sortedSegments)-i-1; j++ {
			if sortedSegments[j].SegmentID > sortedSegments[j+1].SegmentID {
				sortedSegments[j], sortedSegments[j+1] = sortedSegments[j+1], sortedSegments[j]
			}
		}
	}

	// 验证SegmentID是否连续（从1开始）
	for i, seg := range sortedSegments {
		if seg.SegmentID != i+1 {
			return nil, fmt.Errorf("non-consecutive segment IDs: expected %d, got %d", i+1, seg.SegmentID)
		}
	}

	return sortedSegments, nil
}

// GetObject 从卷中读取对象数据，支持跨卷读取
func (as *AppendStorage) GetObject(bucket, key string, segments []VolumeSegment) (io.ReadCloser, error) {
	// 验证并排序片段
	sortedSegments, err := ValidateAndSortSegments(segments)
	if err != nil {
		return nil, fmt.Errorf("invalid segments: %w", err)
	}

	// 如果只有一个片段，使用简单的单卷读取
	if len(sortedSegments) == 1 {
		segment := sortedSegments[0]

		// 获取volume读锁
		volumeLock := as.getVolumeLock(segment.VolumeID)
		volumeLock.RLock()
		defer volumeLock.RUnlock()

		as.volumesMu.RLock()
		volume, exists := as.volumes[segment.VolumeID]
		as.volumesMu.RUnlock()

		if !exists {
			return nil, fmt.Errorf("volume %d not found", segment.VolumeID)
		}

		return as.readFromVolumeWithLock(volume, segment.Offset, segment.Size)
	}

	// 多个片段，创建多卷读取器
	return &multiVolumeReader{
		appendStorage: as,
		segments:      sortedSegments,
		currentIndex:  0,
	}, nil
}

// GetObjectLegacy 向后兼容的单卷读取方法
func (as *AppendStorage) GetObjectLegacy(bucket, key string, volumeID int, offset, size int64) (io.ReadCloser, error) {
	// 获取volume读锁
	volumeLock := as.getVolumeLock(volumeID)
	volumeLock.RLock()
	defer volumeLock.RUnlock()

	as.volumesMu.RLock()
	volume, exists := as.volumes[volumeID]
	as.volumesMu.RUnlock()

	if !exists {
		return nil, fmt.Errorf("volume %d not found", volumeID)
	}

	return as.readFromVolumeWithLock(volume, offset, size)
}

// volumeReader 包装文件读取器
type volumeReader struct {
	file   *os.File
	reader io.Reader
}

func (vr *volumeReader) Read(p []byte) (n int, err error) {
	return vr.reader.Read(p)
}

func (vr *volumeReader) Close() error {
	return vr.file.Close()
}

// multiVolumeReader 支持跨卷读取的读取器
type multiVolumeReader struct {
	appendStorage *AppendStorage
	segments      []VolumeSegment
	currentIndex  int
	currentReader io.ReadCloser
	currentLock   *sync.RWMutex // 当前卷的锁
}

func (mvr *multiVolumeReader) Read(p []byte) (n int, err error) {
	// 如果没有当前读取器，尝试打开下一个片段
	if mvr.currentReader == nil {
		if mvr.currentIndex >= len(mvr.segments) {
			return 0, io.EOF
		}

		segment := mvr.segments[mvr.currentIndex]

		// 获取当前卷的读锁
		mvr.currentLock = mvr.appendStorage.getVolumeLock(segment.VolumeID)
		mvr.currentLock.RLock()

		mvr.appendStorage.volumesMu.RLock()
		volume, exists := mvr.appendStorage.volumes[segment.VolumeID]
		mvr.appendStorage.volumesMu.RUnlock()

		if !exists {
			mvr.currentLock.RUnlock()
			return 0, fmt.Errorf("volume %d not found", segment.VolumeID)
		}

		mvr.currentReader, err = mvr.appendStorage.readFromVolumeWithLock(volume, segment.Offset, segment.Size)
		if err != nil {
			mvr.currentLock.RUnlock()
			return 0, err
		}
	}

	// 从当前读取器读取数据
	n, err = mvr.currentReader.Read(p)

	// 如果当前片段读取完毕，关闭当前读取器并移动到下一个片段
	if err == io.EOF {
		mvr.currentReader.Close()
		mvr.currentReader = nil
		if mvr.currentLock != nil {
			mvr.currentLock.RUnlock()
			mvr.currentLock = nil
		}
		mvr.currentIndex++
		// 如果还有更多片段，返回0而不是EOF，让下次调用继续读取
		if mvr.currentIndex < len(mvr.segments) {
			return n, nil
		}
	}

	return n, err
}

func (mvr *multiVolumeReader) Close() error {
	if mvr.currentReader != nil {
		err := mvr.currentReader.Close()
		if mvr.currentLock != nil {
			mvr.currentLock.RUnlock()
		}
		return err
	}
	return nil
}

// DeleteObject 在append模式下，删除只是标记删除，不实际删除数据
func (as *AppendStorage) DeleteObject(bucket, key string) error {
	// 在append模式下，我们暂时不实现真正的删除
	// 只是返回成功，表示对象已被"删除"
	return nil
}

// GetVolumeInfo 获取卷信息
func (as *AppendStorage) GetVolumeInfo(volumeID int) (*VolumeInfo, error) {
	as.volumesMu.RLock()
	defer as.volumesMu.RUnlock()

	volume, exists := as.volumes[volumeID]
	if !exists {
		return nil, fmt.Errorf("volume %d not found", volumeID)
	}

	// 返回副本以避免并发修改
	volumeCopy := *volume
	return &volumeCopy, nil
}

// ListVolumes 列出所有卷
func (as *AppendStorage) ListVolumes() []*VolumeInfo {
	as.volumesMu.RLock()
	defer as.volumesMu.RUnlock()

	volumes := make([]*VolumeInfo, 0, len(as.volumes))
	for _, volume := range as.volumes {
		// 返回副本
		volumeCopy := *volume
		volumes = append(volumes, &volumeCopy)
	}

	return volumes
}

// 垃圾回收相关方法

// GetDeletedSegmentsByVolume 获取指定卷中所有已删除对象的数据段信息
func (as *AppendStorage) GetDeletedSegmentsByVolume(volumeID int, deletedRecords []DeletedObjectRecord) []VolumeSegment {
	var segments []VolumeSegment

	for _, record := range deletedRecords {
		if len(record.Segments) > 0 {
			// 多片段对象
			for _, seg := range record.Segments {
				if seg.VolumeID == volumeID {
					segments = append(segments, seg)
				}
			}
		} else if record.VolumeID == volumeID {
			// 单卷对象（向后兼容）
			segments = append(segments, VolumeSegment{
				SegmentID: 1,
				VolumeID:  record.VolumeID,
				Offset:    record.Offset,
				Size:      record.Size,
			})
		}
	}

	return segments
}

// CalculateReclaimableSpace 计算指定卷中可以回收的空间大小
func (as *AppendStorage) CalculateReclaimableSpace(volumeID int, deletedRecords []DeletedObjectRecord) int64 {
	segments := as.GetDeletedSegmentsByVolume(volumeID, deletedRecords)

	var totalSize int64
	for _, seg := range segments {
		totalSize += seg.Size
	}

	return totalSize
}

// GetVolumeUtilization 获取卷的利用率信息
func (as *AppendStorage) GetVolumeUtilization(volumeID int, deletedRecords []DeletedObjectRecord) (used, deleted, total int64, utilization float64) {
	as.volumesMu.RLock()
	volume, exists := as.volumes[volumeID]
	as.volumesMu.RUnlock()

	if !exists {
		return 0, 0, 0, 0
	}

	used = volume.Used
	total = volume.Size
	deleted = as.CalculateReclaimableSpace(volumeID, deletedRecords)

	if total > 0 {
		utilization = float64(used) / float64(total) * 100
	}

	return used, deleted, total, utilization
}

// ListVolumeUtilization 列出所有卷的利用率信息
func (as *AppendStorage) ListVolumeUtilization(deletedRecords []DeletedObjectRecord) map[int]VolumeUtilizationInfo {
	as.volumesMu.RLock()
	defer as.volumesMu.RUnlock()

	utilization := make(map[int]VolumeUtilizationInfo)

	for volumeID := range as.volumes {
		used, deleted, total, util := as.GetVolumeUtilization(volumeID, deletedRecords)
		utilization[volumeID] = VolumeUtilizationInfo{
			VolumeID:    volumeID,
			Used:        used,
			Deleted:     deleted,
			Total:       total,
			Utilization: util,
			Reclaimable: deleted,
		}
	}

	return utilization
}

// VolumeUtilizationInfo 卷利用率信息
type VolumeUtilizationInfo struct {
	VolumeID    int     `json:"volume_id"`
	Used        int64   `json:"used"`        // 已使用空间
	Deleted     int64   `json:"deleted"`     // 已删除对象占用的空间
	Total       int64   `json:"total"`       // 总空间
	Utilization float64 `json:"utilization"` // 利用率百分比
	Reclaimable int64   `json:"reclaimable"` // 可回收空间
}
